<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>实时流式文字传输</title>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      body {
        font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        min-height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
        padding: 20px;
      }

      .container {
        width: 100%;
        max-width: 900px;
        background: white;
        border-radius: 12px;
        box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
        overflow: hidden;
      }

      .header {
        background: #2d3748;
        color: white;
        padding: 20px;
        text-align: center;
      }

      .content {
        padding: 20px;
      }

      .stream-container {
        display: flex;
        gap: 20px;
        margin-bottom: 20px;
      }

      .input-section,
      .output-section {
        flex: 1;
      }

      .section-title {
        font-size: 16px;
        font-weight: 600;
        margin-bottom: 10px;
        color: #2d3748;
      }

      textarea {
        width: 100%;
        height: 120px;
        padding: 12px;
        border: 2px solid #e2e8f0;
        border-radius: 8px;
        resize: vertical;
        font-family: monospace;
        font-size: 14px;
      }

      textarea:focus {
        outline: none;
        border-color: #4299e1;
      }

      .stream-display {
        height: 300px;
        border: 2px solid #e2e8f0;
        border-radius: 8px;
        padding: 16px;
        overflow-y: auto;
        background: #f7fafc;
        font-family: "Segoe UI", sans-serif;
        font-size: 16px;
        line-height: 1.6;
        white-space: pre-wrap;
      }

      .cursor {
        display: inline-block;
        width: 8px;
        height: 18px;
        background: #4299e1;
        animation: blink 1s infinite;
        vertical-align: middle;
      }

      @keyframes blink {
        0%,
        50% {
          opacity: 1;
        }
        51%,
        100% {
          opacity: 0;
        }
      }

      .controls {
        display: flex;
        gap: 12px;
        margin-bottom: 20px;
        flex-wrap: wrap;
      }

      button {
        padding: 12px 24px;
        border: none;
        border-radius: 6px;
        cursor: pointer;
        font-weight: 500;
        transition: all 0.2s;
        flex: 1;
        min-width: 140px;
      }

      .btn-start {
        background: #48bb78;
        color: white;
      }

      .btn-start:hover:not(:disabled) {
        background: #38a169;
        transform: translateY(-1px);
      }

      .btn-stop {
        background: #f56565;
        color: white;
      }

      .btn-stop:hover:not(:disabled) {
        background: #e53e3e;
        transform: translateY(-1px);
      }

      button:disabled {
        opacity: 0.6;
        cursor: not-allowed;
        transform: none !important;
      }

      .stats {
        display: flex;
        gap: 15px;
        background: #edf2f7;
        padding: 15px;
        border-radius: 8px;
        margin-bottom: 15px;
      }

      .stat-item {
        flex: 1;
        text-align: center;
        padding: 10px;
        background: white;
        border-radius: 6px;
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
      }

      .stat-value {
        font-size: 24px;
        font-weight: bold;
        color: #4299e1;
      }

      .stat-label {
        font-size: 12px;
        color: #718096;
        margin-top: 4px;
      }

      .status {
        text-align: center;
        padding: 12px;
        background: #ebf8ff;
        border-radius: 6px;
        font-size: 14px;
        color: #3182ce;
        margin-top: 15px;
        font-weight: 500;
      }

      .progress-bar {
        width: 100%;
        height: 6px;
        background: #e2e8f0;
        border-radius: 3px;
        overflow: hidden;
        margin: 10px 0;
      }

      .progress-fill {
        height: 100%;
        background: linear-gradient(90deg, #48bb78, #4299e1);
        transition: width 0.3s ease;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <div class="container">
        <div class="header">
          <h1>实时流式文字传输演示</h1>
          <p>边接收边展示 - 无需等待完整内容</p>
        </div>

        <div class="content">
          <div class="stats">
            <div class="stat-item">
              <div class="stat-value">{{ receivedChars }}</div>
              <div class="stat-label">已接收字符</div>
            </div>
            <div class="stat-item">
              <div class="stat-value">{{ displayedChars }}</div>
              <div class="stat-label">已显示字符</div>
            </div>
            <div class="stat-item">
              <div class="stat-value">{{ speed }}字/秒</div>
              <div class="stat-label">实时速度</div>
            </div>
          </div>

          <div class="stream-container">
            <div class="input-section">
              <div class="section-title">输入内容（模拟服务器数据流）</div>
              <textarea v-model="inputText" placeholder="请输入要流式传输的内容..."></textarea>
            </div>

            <div class="output-section">
              <div class="section-title">实时输出展示</div>
              <div class="stream-display" ref="displayRef">{{ displayedContent }}<span class="cursor" v-if="isStreaming"></span></div>
            </div>
          </div>

          <div class="progress-bar">
            <div class="progress-fill" :style="{ width: progress + '%' }"></div>
          </div>

          <div class="controls">
            <button class="btn-start" @click="startRealStream" :disabled="isStreaming">{{ isStreaming ? '传输中...' : '开始实时传输' }}</button>
            <button class="btn-stop" @click="stopStream" :disabled="!isStreaming">停止传输</button>
            <button @click="simulateNetworkStream" :disabled="isStreaming">模拟网络流</button>
          </div>

          <div class="status">{{ statusMessage }}</div>
        </div>
      </div>
    </div>

    <script>
      const { createApp, ref, onMounted, onUnmounted, nextTick } = Vue;

      createApp({
        setup() {
          const inputText = ref(
            "欢迎使用实时流式文字传输系统！这是一种先进的文本处理技术，可以在数据还在传输过程中就逐步展示给用户，无需等待完整内容下载完成。这种技术广泛应用于聊天应用、实时日志监控、新闻推送等场景。"
          );
          const displayedContent = ref("");
          const isStreaming = ref(false);
          const statusMessage = ref("准备就绪");
          const displayRef = ref(null);
          const receivedChars = ref(0);
          const displayedChars = ref(0);
          const speed = ref(0);
          const progress = ref(0);

          let streamController = null;
          let lastUpdateTime = 0;
          let charsInSecond = 0;
          let speedInterval = null;
          
          async function sendChatStreamData(pramas: any) {
            const url = `${BASEURL}/v3/chat?conversation_id=${pramas.conversation_id}`;
            const response = await fetch(url, {
              method: "POST",
              body: JSON.stringify(pramas),
              headers: { Accept: "application/json", "Content-Type": "application/json", Authorization: `Bearer ${TOKEN}` },
            });
            const reader = response?.body?.getReader();
            const textDecoder = new TextDecoder();

            let done = false;
            while (!done) {
              const { value, done: doneReading } = await reader.read();
              done = doneReading;
              if (value) {
                // 可以实时处理后端返回的每一块数据
                console.log(textDecoder.decode(value));
                // 你的处理逻辑
              }
            }
            console.log("数据读取完毕");
          }

          // 模拟真实的网络流式传输
          const simulateNetworkStream = async () => {
            if (!inputText.value.trim()) {
              statusMessage.value = "请输入要传输的内容";
              return;
            }

            displayedContent.value = "";
            receivedChars.value = 0;
            displayedChars.value = 0;
            progress.value = 0;
            isStreaming.value = true;
            statusMessage.value = "正在模拟网络流式传输...";

            try {
              // 创建模拟的响应流
              const stream = new ReadableStream({
                start(controller) {
                  streamController = controller;
                  const text = inputText.value;
                  let index = 0;

                  const pushData = () => {
                    if (index < text.length && isStreaming.value) {
                      // 模拟网络传输的不确定性
                      const chunkSize = Math.floor(Math.random() * 3) + 1;
                      const chunk = text.substr(index, chunkSize);

                      controller.enqueue(chunk);
                      receivedChars.value += chunk.length;
                      index += chunk.length;

                      progress.value = (index / text.length) * 100;

                      // 随机延迟模拟网络波动
                      setTimeout(pushData, Math.random() * 100 + 50);
                    } else {
                      controller.close();
                    }
                  };

                  pushData();
                },
              });

              // 处理流数据
              const reader = stream.getReader();
              const decoder = new TextDecoder();

              while (isStreaming.value) {
                const { done, value } = await reader.read();

                if (done) {
                  statusMessage.value = "传输完成";
                  isStreaming.value = false;
                  break;
                }

                // 实时处理并显示数据
                processStreamChunk(value);
              }
            } catch (error) {
              console.error("流处理错误:", error);
              statusMessage.value = "传输出错: " + error.message;
              isStreaming.value = false;
            }
          };

          // 处理流数据块
          const processStreamChunk = (chunk) => {
            displayedContent.value += chunk;
            displayedChars.value = displayedContent.value.length;
            charsInSecond += chunk.length;
            scrollToBottom();
          };

          // 开始实时流式传输
          const startRealStream = async () => {
            if (!inputText.value.trim()) {
              statusMessage.value = "请输入要传输的内容";
              return;
            }

            displayedContent.value = "";
            receivedChars.value = 0;
            displayedChars.value = 0;
            progress.value = 0;
            isStreaming.value = true;
            statusMessage.value = "正在建立流式连接...";

            // 启动速度计算
            startSpeedCalculation();

            try {
              // 这里应该是真实的 fetch 请求
              // const response = await fetch('/your-stream-endpoint', {
              //     method: 'POST',
              //     headers: { 'Content-Type': 'application/json' },
              //     body: JSON.stringify({ text: inputText.value })
              // });

              // 模拟 fetch 响应
              await simulateStreamResponse();
            } catch (error) {
              statusMessage.value = "连接失败: " + error.message;
              isStreaming.value = false;
              stopSpeedCalculation();
            }
          };

          // 模拟流式响应
          const simulateStreamResponse = async () => {
            statusMessage.value = "流式传输中...";
            const text = inputText.value;
            let index = 0;

            while (index < text.length && isStreaming.value) {
              // 模拟流式数据到达
              const chunkSize = Math.floor(Math.random() * 2) + 1;
              const chunk = text.substr(index, chunkSize);

              // 模拟网络延迟
              await new Promise((resolve) => setTimeout(resolve, Math.random() * 80 + 20));

              processStreamChunk(chunk);
              receivedChars.value += chunk.length;
              index += chunk.length;

              progress.value = (index / text.length) * 100;
            }

            if (isStreaming.value) {
              statusMessage.value = "传输完成";
              isStreaming.value = false;
              stopSpeedCalculation();
            }
          };

          // 启动速度计算
          const startSpeedCalculation = () => {
            lastUpdateTime = Date.now();
            charsInSecond = 0;

            speedInterval = setInterval(() => {
              const now = Date.now();
              const elapsed = (now - lastUpdateTime) / 1000;
              speed.value = Math.round(charsInSecond / elapsed);
              charsInSecond = 0;
              lastUpdateTime = now;
            }, 1000);
          };

          // 停止速度计算
          const stopSpeedCalculation = () => {
            if (speedInterval) {
              clearInterval(speedInterval);
              speedInterval = null;
            }
            speed.value = 0;
          };

          const stopStream = () => {
            isStreaming.value = false;
            statusMessage.value = "传输已停止";
            stopSpeedCalculation();

            if (streamController) {
              streamController.close();
              streamController = null;
            }
          };

          const scrollToBottom = () => {
            nextTick(() => {
              if (displayRef.value) {
                displayRef.value.scrollTop = displayRef.value.scrollHeight;
              }
            });
          };

          onUnmounted(() => {
            stopStream();
            stopSpeedCalculation();
          });

          return {
            inputText,
            displayedContent,
            isStreaming,
            statusMessage,
            displayRef,
            receivedChars,
            displayedChars,
            speed,
            progress,
            startRealStream,
            stopStream,
            simulateNetworkStream,
          };
        },
      }).mount("#app");
    </script>
  </body>
</html>
